package pt.inescid.components.policyengine.heimdall.pdp.base;

import java.util.Vector;

import pt.inescid.components.policyengine.heimdall.commons.Log;
import pt.inescid.components.policyengine.heimdall.commons.Utilities;
import pt.inescid.components.policyengine.heimdall.pap.base.DomainDefinition;
import pt.inescid.components.policyengine.heimdall.pdp.PolicyDecision;
import pt.inescid.components.policyengine.heimdall.pip.DomainManager;
import pt.inescid.components.policyengine.heimdall.pip.NodeInfo;

public class DomainInstance implements Cloneable {

	private Vector nodes;
	private DomainDefinition definition;
	private long[] value;
	private boolean[] valueTag;
	
	private PolicyDecision decision;

public PolicyDecision getDecision() {
		return decision;
	}

	//  ----------------------------------------------------------
//  ------------------------   constructor   ------------------------
//  ----------------------------------------------------------
	private DomainInstance() {
	}
		
	public DomainInstance(DomainDefinition definition) {
		this.definition = definition;
		nodes = DomainManager.getNodes(definition);
		valueTag = new boolean[AggValue.NUMBER_OF_VALUE_TYPES];
		
		for (int i = 0; i < AggValue.NUMBER_OF_VALUE_TYPES; i++) {
			valueTag[i] = false;
		}
		
		this.decision = new PolicyDecision();
	}


//  ----------------------------------------------------------
//  ------------------------   toString   ------------------------
//  ----------------------------------------------------------
	public String toString() {
		String result = definition.toString() + "[nodes="; 
		
		if (nodes != null) {
			for (int i = 0; i < nodes.size(); i++) {
				result += ((NodeInfo) nodes.elementAt(i)) + "\n";
			}
		}
		
		result += "]";
		
		return (result);
	}


	public Vector getNodes() {
		if (nodes == null) {
			nodes = DomainManager.getNodes(definition);
		}
		
		return nodes;
	}


	public void setNodes(Vector nodes) {
		this.nodes = nodes;
	}


	public DomainDefinition getDefinition() {
		return definition;
	}


	public void setDefinition(DomainDefinition definition) {
		this.definition = definition;
	}

	//  ----------------------------------------------------------
//  ------------------------   getUnprocessedEvents   ------------------------
//  ----------------------------------------------------------
	public Vector getUnprocessedEvents(ModelInstance currentModel,
			CesInstance cesInstance, 
			Vector cesParameters,
			boolean onlyCached) {

		Log.debug(Log.INFO, "Arrived.", "DomainInstance.getUnprocessedEvents");

		Vector allUnprocessed = new Vector();
		boolean allNodesCollected = true;
		
		decision.setStatus(PolicyDecision.STATUS_FINAL);
		
		if (nodes != null) {
			NodeInfo currentNode = null;
			for (int i = 0; i < nodes.size(); i++) {
				currentNode = (NodeInfo) nodes.elementAt(i);
				Utilities.joinVectors(allUnprocessed, 
						currentNode.getUnprocessedEvents(currentModel, 
								cesInstance, 
								this.definition.getName(),
								cesParameters,
								onlyCached));
				
				if (currentNode.getStatus() == NodeInfo.NODE_WAITING_INFO) {
					allNodesCollected = false;
				}
			}
		}

		if (allNodesCollected) {
			decision.setStatus(PolicyDecision.STATUS_FINAL);
		}
		else {
			decision.setStatus(PolicyDecision.STATUS_WAITING_INFO);
		}
			
		return (allUnprocessed);
	}


	/* ===========================================================
	==============================================================
	=============                    =============================
	=============      getLoadedEvents       =============================
	=============                    =============================
	==============================================================
	=========================================================== */
	public Vector getLoadedEvents(NodeInfo thisNode) {

		Log.debug(Log.INFO, "Arrived.", "DomainInstance.getLoadedEvents");

		Vector result = new Vector();
		if (nodes != null) {
			NodeInfo currentNode = null;
			for (int i = 0; i < nodes.size(); i++) {
				currentNode = (NodeInfo) nodes.elementAt(i);
				
				if (currentNode.equals(thisNode)) {
					return ( 
						currentNode.getLoadedEvents());
				}
			}
		}

		return (null);
	} // getLoadedEvents


	/* ===========================================================
	==============================================================
	=============                    =============================
	=============      resetEvaluation       =============================
	=============                    =============================
	==============================================================
	=========================================================== */
	public void resetEvaluation() {
		
		if (nodes != null) {
			NodeInfo currentNode = null;
			for (int i = 0; i < nodes.size(); i++) {
				currentNode = (NodeInfo) nodes.elementAt(i);
				
				currentNode.setStatus(NodeInfo.NODE_UNDEFINED);
				currentNode.setProcEvents(new Vector());
				currentNode.setUnprocEvents(new Vector());
			}
		}
	}


	
	public Object clone() throws CloneNotSupportedException {
		DomainInstance clonedInstance = new DomainInstance();
		
		NodeInfo currentNode = null;
		clonedInstance.nodes = new Vector();
		for (int i = 0; i < nodes.size(); i++) {
			currentNode = (NodeInfo) nodes.elementAt(i);
			clonedInstance.nodes.add(currentNode.clone());
		}
		
		return (clonedInstance);
	}

	
}; // DomainDefinition
